package com.snails.mall.elasticsearch.biz.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.ruyuan.little.project.common.dto.CommonResponse;
import com.ruyuan.little.project.common.dto.TableData;
import com.snails.mall.elasticsearch.biz.admin.dto.AdminGoodsSpuDTO;
import com.snails.mall.elasticsearch.biz.admin.entity.AdminGoodsSpu;
import com.snails.mall.elasticsearch.biz.admin.service.AdminGoodsService;
import com.snails.mall.elasticsearch.biz.common.constant.QueryFiledNameConstant;
import com.snails.mall.elasticsearch.biz.common.constant.StringPoolConstant;
import com.snails.mall.elasticsearch.biz.common.dao.ElasticsearchDao;
import com.snails.mall.elasticsearch.biz.common.dto.GoodsRelationField;
import com.snails.mall.elasticsearch.biz.common.utils.ElasticClientUtil;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.join.query.HasParentQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author gaoxu
 * date: Created on 2021/11/16 下午2:31
 */

@Service
public class AdminGoodsServiceImpl implements AdminGoodsService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AdminGoodsServiceImpl.class);

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private ElasticsearchDao elasticsearchDao;

    /**
     * 商品index别名
     */
    @Value("${elasticsearch.goodsIndexAlias}")
    private String goodsIndexAlias;

    /**
     * 商品index名称
     */
    @Value("${elasticsearch.goodIndex}")
    private String goodsIndex;

    @Value(value = "classpath:/mapping/goodsIndexFirstVersion.json")
    private Resource goodsIndexMappingResource;

    @PostConstruct
    public void init() throws IOException {
        Boolean goodsIndexExistFlag = elasticsearchDao.indexExistFlag(goodsIndex);
        if (!goodsIndexExistFlag) {
            // 不存在
            Boolean created = elasticsearchDao.createIndex(goodsIndex, goodsIndexAlias, goodsIndexMappingResource);
            LOGGER.info("create index {}", created ? "success" : "fail");
        } else {
            LOGGER.info("index:{} already exist", goodsIndex);
        }
    }

    @Override
    public CommonResponse list(AdminGoodsSpuDTO adminGoodsSpuDTO) {
        LOGGER.info("AdminGoodsServiceImpl list adminGoodsSpuDTO:{}", adminGoodsSpuDTO);

        // 查询参数
        String storeId = adminGoodsSpuDTO.getStoreId();
        Integer page = adminGoodsSpuDTO.getPage();
        Integer size = adminGoodsSpuDTO.getSize();

        // 构建商品分页查询请求体
        SearchSourceBuilder sourceBuilder = this.buildGoodsPageQueryBuilder(storeId, adminGoodsSpuDTO.getGoodsName(), page, size);

        // 查询请求
        SearchRequest searchRequest = new SearchRequest(goodsIndexAlias);
        searchRequest.source(sourceBuilder);

        try {
            LOGGER.info("从es查询商品请求参数:{}", searchRequest.source().toString());
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            // 构造结果
            TableData<AdminGoodsSpu> tableData = this.buildGoodsPageResult(searchResponse);
            LOGGER.info("结束es查询结果:{}", JSON.toJSONString(tableData));
            return CommonResponse.success(tableData);
        } catch (IOException e) {
            LOGGER.error("从es查询店铺列表失败", e);
        }
        return null;
    }

    /**
     * 构建商品分页结果
     *
     * @param searchResponse
     * @return
     */
    private TableData<AdminGoodsSpu> buildGoodsPageResult(SearchResponse searchResponse) {
        TableData<AdminGoodsSpu> tableData = new TableData<>();
        SearchHits hits = searchResponse.getHits();
        long total = hits.getTotalHits().value;
        tableData.setTotal(total);

        List<AdminGoodsSpu> adminGoodsSpuList = new ArrayList<>();
        if (total > 0) {
            // 封装数据
            for (SearchHit hit : hits) {
                AdminGoodsSpu adminGoodsSpu = JSON.parseObject(hit.getSourceAsString(), AdminGoodsSpu.class);
                adminGoodsSpuList.add(adminGoodsSpu);
            }
        }
        tableData.setRows(adminGoodsSpuList);
        return tableData;
    }

    /**
     * 构建分页查询商品信息的请求体
     *
     * @param goodsStoreId
     * @param goodsName
     * @param page
     * @param size
     * @return
     */
    private SearchSourceBuilder buildGoodsPageQueryBuilder(String goodsStoreId, String goodsName, Integer page, Integer size) {
        SearchSourceBuilder sourceBuilder = ElasticClientUtil.builderPageSearchBuilder(page, size);

        QueryBuilder parentQueryBuilder;

        // 商品店铺id不为空,根据id进行筛选 否则查询所有
        if (StringUtils.hasLength(goodsStoreId)) {
            parentQueryBuilder = new TermQueryBuilder(QueryFiledNameConstant.UNDERSCORE_ID, goodsStoreId);
        } else {
            parentQueryBuilder = new MatchAllQueryBuilder();
        }
        HasParentQueryBuilder hasParentQueryBuilder =
                new HasParentQueryBuilder(GoodsRelationField.GOODS_STORE, parentQueryBuilder, false).innerHit(new InnerHitBuilder());
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(hasParentQueryBuilder);

        // 商品名臣是否为空
        if (StringUtils.hasLength(goodsName)) {
            boolQueryBuilder.must(QueryBuilders.wildcardQuery(QueryFiledNameConstant.GOODS_NAME,
                    StringPoolConstant.STAR + goodsName + StringPoolConstant.STAR));
        }
        sourceBuilder.query(boolQueryBuilder);
        return sourceBuilder;
    }

    @Override
    public CommonResponse getSpuDetailById(String id) {
        return null;
    }
}
